﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SafeScript.MetaModel
{
    public class TemplateInstanceTypeDef : Class
    {
        public AbstractType Template;
        public Dictionary<TemplateParameterType, ITypeDef> TemplateArguments = new Dictionary<TemplateParameterType, ITypeDef>();

        public override bool IsEqualTo(ITypeDef typedef)
        {
            TemplateInstanceTypeDef f = typedef as TemplateInstanceTypeDef;
            if (f == null)
                return false;
            if (!this.Template.IsEqualTo(f.Template))
                return false;
            if (this.TemplateArguments.Count != f.TemplateArguments.Count)
                return false;
            foreach (TemplateParameterType tp in this.TemplateArguments.Keys)
            {
                if (!this.TemplateArguments[tp].IsEqualTo(f.TemplateArguments[tp]))
                    return false;
            }
            return true;
        }

        public override void ParseClassMembers(ErrorReport report)
        {
            System.Diagnostics.Debug.Assert(this.Template is AbstractType, "Programming error");
            AbstractType tmpl = this.Template as AbstractType;
            //System.Diagnostics.Debug.Assert(this.TemplateArguments.Count == tmpl.TemplateParameters.Count, "Programming error");

            //this.CheckInheritanceForLoops(report);

            // Instantiate all members by copying them from the templaye
            foreach (object obj in this.Template.ScopeElements.Values)
            {
                if (obj is MemberFunction)
                {
                    MemberFunction func = obj as MemberFunction;
                    MemberFunction func2 = func.Instantiate(this.TemplateArguments) as MemberFunction;
                    func2.Owner = this;
                    this.ScopeElements[func2.Name] = func2;
                }
                else if (obj is MemberFunctionSet)
                {
                    MemberFunctionSet func = obj as MemberFunctionSet;
                    MemberFunctionSet func2 = func.Instantiate(this.TemplateArguments);
                    this.ScopeElements[func2.Name] = func2;
                }
                else if (obj is Property)
                {
                    Property v = obj as Property;
                    Property v2 = v.Instantiate(this.TemplateArguments) as Property;
                    v2.Owner = this;
                    this.ScopeElements[v2.Name] = v2;
                }
                else if (obj is MemberVariable)
                {
                    MemberVariable v = obj as MemberVariable;
                    MemberVariable v2 = v.Instantiate(this.TemplateArguments) as MemberVariable;
                    v2.Owner = this;
                    this.ScopeElements[v2.Name] = v2;
                }
                else if (obj is AbstractType)
                {
                    // Do nothing by intention
                }
                // TODO else
            }
        }

        public override ITypeDef Instantiate(Dictionary<TemplateParameterType, ITypeDef> templateArguments)
        {
            Dictionary<TemplateParameterType,ITypeDef> args = new Dictionary<TemplateParameterType,ITypeDef>();

            bool required = false;
            foreach (TemplateParameterType tp in this.TemplateArguments.Keys)
            {
                ITypeDef ta = this.TemplateArguments[tp];
                if (ta is TemplateParameterType)
                {
                    TemplateParameterType tap = ta as TemplateParameterType;
                    if (templateArguments.ContainsKey(tap))
                    {
                        required = true;
                        args[tp] = templateArguments[tap];
                        continue;
                    }
                }
                args[tp] = ta;
            }

            if (!required)
                return this;

            return Compiler.CurrentCompiler.GetTemplateInstance(this.Template, args);
        }

        //public override ITypeDef Instantiate(List<TemplateParameterType> templateParams, List<ITypeDef> templateArguments)
        //{
        //    return null;
        //    //// First check whether instantiation
        //    //TemplateInstanceTypeDef t = new TemplateInstanceTypeDef();
        //    //this.InstantiateIntern(t, templateParams, TemplateArguments);

        //    //t.Template = this.Template;
        //    //foreach (ITypeDef arg in this.TemplateArguments)
        //    //{
        //    //    bool found = false;
        //    //    for (int i = 0; i < templateParams.Count; ++i)
        //    //    {
        //    //        TemplateParameterType tp = templateParams[i];
        //    //        if (arg == tp)
        //    //        {
        //    //            t.TemplateArguments.Add(tp);
        //    //            found = true;
        //    //            break;
        //    //        }
        //    //    }
        //    //    if (!found)
        //    //        t.TemplateArguments.Add(arg);
        //    //}
        //    //return t;    
        //}
    }
}
